

import 'package:flutter/material.dart';


mixin YkStatusMachineDelegate {

  String getName();

  Widget mainWidget();

  Future<void> reload();

  Future<void> dispose();
}

class YkStatusMachineController {

  YkStatusMachineWidget? _widget;

  Future<void> enterWithName({required String stateName}) async {
    await _widget?._enterWithName(stateName: stateName);
    return;
  }

}

class YkStatusMachineWidget extends StatefulWidget {

  YkStatusMachineController? controller;

  List<YkStatusMachineDelegate> states = [];

  YkStatusMachineWidget({super.key, required this.states, YkStatusMachineController? controller}) {
    controller = controller;
    controller?._widget = this;
  }

  void Function(String name)? callBack = null;

  @override
  State<YkStatusMachineWidget> createState() => _YkStatusMachineWidgetState(states: states, callBack: (void Function(String name) callBack) {
    this.callBack = callBack;
  });

  Future<void> _enterWithName({required String stateName}) async {
    callBack?.call(stateName);
  }
}

class _YkStatusMachineWidgetState extends State<YkStatusMachineWidget> {

  bool _didDispose = false;

  List<YkStatusMachineDelegate> states = [];

  YkStatusMachineDelegate? _currentDelegate = null;

  void Function(void Function(String name)) callBack;

  _YkStatusMachineWidgetState({required this.states, required this.callBack});

  @override
  void initState() {
    _didDispose = false;
    try {
      _currentDelegate = widget.states.first;
    } catch (e) {}
    callBack.call((name) {
      _enterWithName(stateName: name);
    });
    super.initState();
  }

  @override
  void dispose() {
    _didDispose = true;
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: _currentDelegate?.mainWidget() ?? Container(),
    );
  }

  Future<void> _enterWithName({required String stateName}) async {

    if (_didDispose) {
      return;
    }

    try {
      final delegate = widget.states.firstWhere((e) {
        return e.getName() == stateName;
      });

      if (_currentDelegate?.getName() != delegate.getName()) {

        await _currentDelegate?.dispose();

        _currentDelegate = delegate;
      }

      await _currentDelegate?.reload();

      setState(() {

      });
    } catch (e) {

    }

    return Future.value();
  }
}

